package LsEngine

import (
	"crypto/md5"
	"fmt"
	"io"
	"net"
	"time"
)

import (
	. "LsDb"
	"tksDB"
	. "tksLog"
	. "tksStatic"
	. "tksTcp"
	. "tksUint"
)

// type TokenInfo struct {
// 	Uid      int
// 	Username string
// }

type TbUser struct {
	Uid      int `PK`
	Username string
	Pwd      string
}

var users map[string]*TbUser

func LoadUser() {
	users = make(map[string]*TbUser)
	//
	var allusers []TbUser
	Db.GetAllDataFromMysql(&allusers)
	for i := 0; i < len(allusers); i++ {
		newuser := new(TbUser)
		newuser.Uid = allusers[i].Uid
		newuser.Username = allusers[i].Username
		newuser.Pwd = allusers[i].Pwd
		users[newuser.Username] = newuser
	}
}

func (u *TbUser) Verify(pwd string) bool {
	return u.Pwd == pwd
}

func (u *TbUser) SaveToken() string {
	h := md5.New()
	io.WriteString(h, u.Username)
	io.WriteString(h, fmt.Sprintf("%ld", time.Now().Unix()))
	io.WriteString(h, u.Pwd)
	token := fmt.Sprintf("%x", h.Sum(nil))

	info := TokenInfo{u.Uid, u.Username}
	Cache.Hset(token, &info)
	return token
}

func EncodePwd(user string, pwd string) string {
	h := md5.New()
	salt1 := "f4g*h(j"
	salt2 := "1^2&4*(d)"
	io.WriteString(h, salt1)
	io.WriteString(h, user)
	io.WriteString(h, salt2)
	io.WriteString(h, pwd)

	return fmt.Sprintf("%x", h.Sum(nil))
}

func sendRsp(conn net.Conn, cmd uint32, ret Ret, token string) {
	var rsp LoginRsp

	rsp.R = ret
	if ret == RetSucc {
		rsp.Token = token
		rsp.GateAddr = tksDB.GetAviableGate(&Cache.Redis)
	}
	data, _ := MsgToBuf(rsp)
	Debug("send rsp, cmd: %d, data: %s", cmd, string(data))
	SendBuffer(conn, cmd, 0, 0, data)
}

func findUser(username string) *TbUser {
	info, ok := users[username]
	if ok {
		return info
	} else {
		return nil
	}
}

func saveUser(username string, user *TbUser) error {
	users[user.Username] = user
	return Db.SetDataIntoMysql(user)
}

func Login(conn net.Conn, from uint32, to uint32, buf []byte) {
	defer conn.Close()
	//
	json, err := BufToMsg(buf)
	if err != nil {
		sendRsp(conn, CmdLoginRsp, RetMsgFormatError, "")
		return
	}
	name := json.Get("User").MustString()
	pwd := json.Get("Pwd").MustString()
	//
	user := findUser(name)
	if user != nil {
		if !user.Verify(EncodePwd(name, pwd)) {
			sendRsp(conn, CmdLoginRsp, RetPwdError, "")
			return
		}
		//
		Debug("old user: %s login from %s", name, conn.RemoteAddr().String())
		token := user.SaveToken()
		sendRsp(conn, CmdLoginRsp, RetSucc, token)
		return

	} else {
		sendRsp(conn, CmdLoginRsp, RetUserNotExists, "")
		return
	}
}

func Enroll(conn net.Conn, from uint32, to uint32, buf []byte) {
	defer conn.Close()
	//
	json, err := BufToMsg(buf)
	if err != nil {
		sendRsp(conn, CmdEnrollRsp, RetMsgFormatError, "")
		return
	}
	name := json.Get("User").MustString()
	pwd := json.Get("Pwd").MustString()
	//
	user := findUser(name)
	if user != nil {
		sendRsp(conn, CmdEnrollRsp, RetUserExists, "")
		return
	} else {
		user = new(TbUser)
		user.Username = name
		user.Pwd = EncodePwd(name, pwd)
		//
		err = saveUser(name, user)
		Debug("new user: %s pwd: %s, id: %d enroll from %s", name, pwd, user.Uid, conn.RemoteAddr().String())
		if err != nil {
			sendRsp(conn, CmdEnrollRsp, RetMsgFormatError, "")
			return
		}
		token := user.SaveToken()
		//
		sendRsp(conn, CmdEnrollRsp, RetSucc, token)
		return
	}
}
